package org.custom.spring.boot.datasource.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.custom.spring.boot.datasource.annotation.DatasourceSelection;
import org.custom.spring.boot.datasource.entity.datasource.DynamicDatasourceSelection;
import org.custom.spring.boot.datasource.manager.DataSourceManager;
import org.custom.spring.boot.datasource.service.DynamicDatasourceService;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Objects;

/**
 * DatasourceAspect
 *
 * @author 李坤
 * @date 2022/3/31 10:21
 */
@Aspect
@Order(-1)
@Component
public class DataSourceAspect {
    @Resource
    private DynamicDatasourceService dynamicDatasourceService;

    /**
     * 将数据源选择的权力移交给DataSourceManager
     * <p>
     * 注：数据源选择规则 ---> 如果在AOP执行前DataSourceManager中未指定数据源，则使用@DatasourceSelection注解中的数据源选择规则
     * <p>
     * 注：设置 AOP 的拦截顺序
     *
     * @param joinPoint 切面
     *
     * @throws Throwable 方法执行过程中可能出现的异常信息
     */
    @Order(9)
    @Before("@annotation(org.custom.spring.boot.datasource.annotation.DatasourceSelection)")
    public void ChooseDatasource(JoinPoint joinPoint) throws Throwable {
        DynamicDatasourceSelection dynamicDatasourceSelection = DataSourceManager.getDynamicDatasourceSelection();
        // 判断线程中是否已指定数据源
        if (Objects.isNull(dynamicDatasourceSelection)) {
            // 数据源名称
            String dataSourceName;
            // 获取被拦截的方法
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            // 获取被拦截方法上的注解，并将值放入到 DataSourceManager 中
            DatasourceSelection datasourceSelection = signature.getMethod().getAnnotation(DatasourceSelection.class);
            // 根据 datasourceSelection 注解配置构建 DynamicDatasourceSelection 对象
            dynamicDatasourceSelection = new DynamicDatasourceSelection(datasourceSelection.value(), datasourceSelection.userDefaultDataSource());

            // 将给定的设置数据源到 DataSourceManager 中
            DataSourceManager.setDynamicDatasourceSelection(dynamicDatasourceSelection);
        }
        // 校验给定名称的数据源是否存在
        dynamicDatasourceService.verifyDynamicDataSourceSelection(dynamicDatasourceSelection);
    }
}
